home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / curses.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  21KB  |  1,019 lines

  1. /*
  2.  * Intelligent session manager using curses.  Options include ANSI X3.64
  3.  * emulation with both VTx00 and PC graphics.
  4.  *
  5.  * Brandon S. Allbery KF8NH
  6.  * No copyright, copyleft, copysideways, copytwisted, ....
  7.  */
  8.  
  9. #include <curses.h>
  10. #include <term.h>
  11. #undef FALSE
  12. #undef TRUE
  13.  
  14. /* This nonsense WILL go away... */
  15. #ifdef linux
  16. #define _tmarg _regtop
  17. #define _bmarg _regbottom
  18. #define wbkgdset(w,attr) ((w)->_bkgd = (attr))
  19. #ifndef getattrs
  20. #define getattrs(w) ((w)->_attrs)
  21. #endif
  22. #endif
  23.  
  24. #include "hardware.h"
  25. #include "proc.h"
  26. #include "socket.h"
  27. #undef tputs
  28. #include "tty.h"
  29. #include "sessmgr.h"
  30. #include "config.h"
  31.  
  32. #ifdef SM_CURSES
  33.  
  34. #ifdef linux
  35. extern int isatty __ARGS((int));
  36. #endif
  37.  
  38. extern struct sessmgr_sw curses_sessmgr; /* forward declaration */
  39.  
  40. static int Suspense, initted;
  41. static TERMINAL *my_term;
  42. static void *curscreen;
  43.  
  44. #if 0
  45. /* colors - this is a mess */
  46. static char *color_pair_map;
  47. #endif
  48.  
  49. struct keytrie
  50. {
  51.     enum {KT_DEF, KT_TRIE, KT_TVAL, KT_VAL} kt_type; /* type of entry */
  52.     int kt_tval;        /* if a TVAL, the timed-out value */
  53.     union
  54.     {
  55.     struct keytrie *ktu_trie; /* sub-trie */
  56. #define kt_trie kt_u.ktu_trie
  57.     int ktu_val;        /* value */
  58. #define kt_val kt_u.ktu_val
  59.     } kt_u;
  60. };
  61.  
  62. struct curses_data
  63. {
  64.     WINDOW *win;
  65.     struct
  66.     {
  67.     int x, y, tmarg, bmarg, valid;
  68.     chtype attr, bkgd;
  69.     } save;
  70.     char parm[8];
  71.     char nparm;
  72.     char bg;            /* current background */
  73.     char fg;            /* current foreground */
  74.     char flags;
  75. #define C_ESC        0x01
  76. #define C_CSI        0x02
  77. #define C_INS        0x04
  78. #define C_TTY        0x08
  79. #define C_BOLD        0x10
  80. };
  81.  
  82. static struct keytrie *keys;
  83.  
  84. /* mapping of IBM line-drawing characters to curses line drawing */
  85. /* this is evil: it doesn't use e.g. ACS_HLINE because that's an array ref */
  86. static chtype ibm_map[128] =
  87. {
  88.      0,   0,   0,   0,   0,   0,   0,   0,
  89.      0,   0,   0,   0,   0,   0,   0,   0,
  90.      0,   0,   0,   0,   0,   0,   0,   0,
  91.      0,   0,   0,   0,   0,   0,   0,   0,
  92.      0,   0,   0,   0,   0,   0,   0,   0,
  93.      0,   0,   0,   0,   0,   0,   0,   0,
  94.     'a', 'a', 'a', 'x', 'u', 'u', 'u', 'k',
  95.     'k', 'u', 'x', 'k', 'j', 'j', 'j', 'k',
  96.     'm', 'v', 'w', 'u', 'q', 'n', 'u', 'u',
  97.     'j', 'l', 'v', 'w', 'u', 'q', 'n', 'v',
  98.     'v', 'w', 'w', 'm', 'm', 'l', 'l', 'n',
  99.     'n', 'j', 'l',  0,   0,   0,   0,   0,
  100.      0,   0,   0,   0,   0,   0,   0,   0,
  101.      0,   0,   0,   0,   0,   0,   0,   0,
  102.      0,   0,   0,   0,   0,   0,   0,   0,
  103.      0,   0,   0,   0,   0,   0,   0,   0,
  104. };
  105.  
  106. #ifdef M_UNIX
  107. #define Getmaxy(w) getmaxy(w)
  108. #define Getmaxx(w) getmaxx(w)
  109. #else
  110.  
  111. static int
  112. Getmaxy(WINDOW *w)
  113. {
  114.     int y, x;
  115.  
  116.     getmaxyx(w, y, x);
  117.     return y;
  118. }
  119.  
  120. static int
  121. Getmaxx(WINDOW *w)
  122. {
  123.     int y, x;
  124.  
  125.     getmaxyx(w, y, x);
  126.     return x;
  127. }
  128.  
  129. #endif
  130.  
  131. static struct keytrie *
  132. key_init(void)
  133. {
  134.     struct keytrie *k;
  135.     int i;
  136.  
  137.     k = mallocw(256 * sizeof *keys);
  138.     for (i = 256; i--; )
  139.     {
  140.     k[i].kt_type = KT_DEF;
  141.     k[i].kt_val = i;
  142.     }
  143.     return k;
  144. }
  145.  
  146. static void
  147. key_add(const char *str, int val)
  148. {
  149.     const char *old;
  150.     struct keytrie *t;
  151.     int c;
  152.  
  153.     /*
  154.      * Follow the trie until we get to the right subtrie for the string, then
  155.      * add the value.  If we hit a KT_DEF, expand the trie.  If we hit a KT_VAL
  156.      * change it to a KT_TVAL, which times out as a KT_VAL but continues as a
  157.      * KT_TRIE.  If given a value for a KT_TRIE, change it to a KT_TVAL.
  158.      */
  159.     if (!str || !*str)
  160.     return;            /* no key to define */
  161.     old = str;
  162.     t = keys;
  163.     while (str[1])
  164.     {
  165.     c = uchar(*str++);
  166.     if (t[c].kt_type != KT_TRIE)
  167.     {
  168.         if (t[c].kt_type == KT_DEF)
  169.         t[c].kt_type = KT_TRIE;
  170.         else
  171.         {
  172.         t[c].kt_type = KT_TVAL;
  173.         t[c].kt_tval = t[c].kt_val;
  174.         }
  175.         t[c].kt_trie = key_init();
  176.     }
  177.     t = t[c].kt_trie;
  178.     }
  179.     c = uchar(*str);
  180.     if (t[c].kt_type == KT_TRIE)
  181.     {
  182.     t[c].kt_type = KT_TVAL;
  183.     t[c].kt_tval = val;
  184.     }
  185.     else if (t[c].kt_type == KT_DEF)
  186.     {
  187.     t[c].kt_type = KT_VAL;
  188.     t[c].kt_val = val;
  189.     }
  190. }
  191.  
  192. #if 0
  193.  
  194. static int
  195. map_colors(int bg, int fg)
  196. {
  197.     int cp, cmask;
  198.  
  199.     if (!color_pair_map)
  200.     return 0;
  201. fprintf(stderr, "map_colors %d %d", bg, fg);
  202.     cmask = (bg << 4) | fg;
  203.     for (cp = 0; cp < COLOR_PAIRS; cp++)
  204.     {
  205.     if (color_pair_map[cp] == -1 || color_pair_map[cp] == cmask)
  206.         break;
  207.     }
  208.     if (cp == COLOR_PAIRS)
  209. {fprintf(stderr, " - out of pairs!\n");
  210.     return 0;
  211. }
  212.     if (color_pair_map[cp] == -1)
  213.     {
  214.     if (init_pair(cp + 1, fg, bg) == ERR)
  215. {fprintf(stderr, "can't create pair %d\n", cp);
  216.         cp = 0;
  217. }
  218.     else
  219. {fprintf(stderr, " - new pair %d\n", cp);
  220.         color_pair_map[cp] = cmask;
  221. }
  222.     }
  223. else fprintf(stderr, " is pair %d\n", cp);
  224.     return COLOR_PAIR((cp + 1));
  225. }
  226.  
  227. #endif
  228.  
  229. static int
  230. curses_init(const struct sessmgr_sw *sm)
  231. {
  232.     extern int Numrows, Numcols;
  233.  
  234.     if (!isatty(0))
  235.     return 0;
  236.     if (initted)
  237.     {
  238. #ifdef RAW_SESSMGR
  239.     set_curterm(my_term);
  240. #endif
  241.     refresh();        /* bring curses back to life */
  242.     }
  243.     else
  244.     {
  245.     initscr();            /* be nice to trap errors... */
  246. #if 0
  247.     /*
  248.      * I assume the curses manpage tells the truth when it claims that
  249.      * colors are initialized to RGB defaults.  If not, I may need to set
  250.      * up the colors in question...
  251.      */
  252.     if (has_colors() && start_color() != ERR && COLORS >= 8)
  253.     {
  254.         color_pair_map = mallocw(COLOR_PAIRS * sizeof *color_pair_map);
  255.         memset(color_pair_map, -1, COLOR_PAIRS * sizeof *color_pair_map);
  256.         map_colors(COLOR_BLACK, COLOR_WHITE); /* default color pair */
  257.     }
  258. #endif
  259.     my_term = cur_term;
  260.     noecho();
  261.     nonl();
  262.     raw();
  263.     keys = key_init();
  264.     key_add(key_down, DNARROW);
  265.     key_add(key_f1, -3);
  266.     key_add(key_f2, -4);
  267.     key_add(key_f3, -5);
  268.     key_add(key_f4, -6);
  269.     key_add(key_f5, -7);
  270.     key_add(key_f6, -8);
  271.     key_add(key_f7, -9);
  272.     key_add(key_f8, -10);
  273.     key_add(key_f9, -11);
  274. #ifdef M_UNIX
  275.     /* SCO botches it, as per usual */
  276.     key_add(key_f0, -2);
  277. #else
  278.     key_add(key_f10, -2);
  279. #endif
  280.     key_add(key_left, LTARROW);
  281.     key_add(key_right, RTARROW);
  282.     key_add(key_up, UPARROW);
  283.     key_add("\177", '\b');    /* so DEL behaves as BS */
  284.     initted = 1;
  285.     }
  286.     Suspense = 0;
  287.     Numrows = LINES;
  288.     Numcols = COLS;
  289.     return 1;
  290. }
  291.  
  292. static void
  293. curses_end(const struct sessmgr_sw *sm)
  294. {
  295.     if (!Suspense)
  296.     endwin();
  297. }
  298.  
  299. static void
  300. curses_suspend(const struct sessmgr_sw *sm)
  301. {
  302.     if (!Suspense++)
  303.     {
  304.     /* note that we use stdscr for this, since it's otherwise unoccupied */
  305.     clear();
  306.     refresh();
  307.     endwin();
  308.     }
  309. }
  310.  
  311. static void
  312. curses_resume(const struct sessmgr_sw *sm)
  313. {
  314.     extern int Numrows, Numcols;
  315.  
  316.     if (!--Suspense)
  317.     {
  318. #ifdef RAW_SESSMGR
  319.     set_curterm(my_term);
  320. #endif
  321.     clearok(((struct curses_data *) curscreen)->win, TRUE);
  322.     wrefresh(((struct curses_data *) curscreen)->win);
  323.     Numrows = LINES;
  324.     Numcols = COLS;
  325.     }
  326. }
  327.  
  328. /*
  329.  * Options supported:
  330.  *
  331.  * tty, ansi
  332.  *    Select old glass-tty emulation or new ANSI X3.64 emulation
  333.  *
  334.  * bold
  335.  *    Specify style of highlight used
  336.  */
  337.  
  338. static char *
  339. curses_opts(const struct sessmgr_sw *sm, void *sp, char *opts)
  340. {
  341.     struct curses_data *cp;
  342.     static char buf[1024];
  343.     char *xp, *ep;
  344.     size_t l;
  345.  
  346.     cp = (struct curses_data *) sp;
  347.     if (!opts)
  348.     {
  349.     /* return printable version of options */
  350.     buf[0] = '\0';
  351.     if (cp->flags & C_TTY)
  352.         strcpy(buf, "tty");
  353.     if ((cp->flags & (C_TTY|C_BOLD)) == (C_TTY|C_BOLD))
  354.         strcat(buf, ",");
  355.     if (cp->flags & C_BOLD)
  356.         strcat(buf, "bold");
  357.     return buf;
  358.     }
  359.     /* parse and set options */
  360.     xp = opts;
  361.     while (*xp)
  362.     {
  363.     while (isspace(*xp) || *xp == ',')
  364.         xp++;
  365.     if (!*xp)
  366.         break;
  367.     l = 0;
  368.     for (ep = xp; *ep && *ep != ',' && !isspace(*ep); ep++)
  369.         l++;
  370.     memcpy(buf, xp, l);
  371.     buf[l] = '\0';
  372.     if (strcasecmp(buf, "tty") == 0)
  373.         cp->flags |= C_TTY;
  374.     else if (strcasecmp(buf, "ansi") == 0)
  375.         cp->flags &= ~C_TTY;
  376.     else if (strcasecmp(buf, "notty") == 0)
  377.         cp->flags &= ~C_TTY;
  378.     else if (strcasecmp(buf, "noansi") == 0)
  379.         cp->flags |= C_TTY;
  380.     else if (strcasecmp(buf, "bold") == 0)
  381.         cp->flags |= C_BOLD;
  382.     else if (strcasecmp(buf, "nobold") == 0)
  383.         cp->flags &= ~C_BOLD;
  384.     else
  385.         tprintf("curses: unknown option \"%s\"\n", buf);
  386.     xp = ep;
  387.     }
  388.     
  389.     return 0;
  390. }
  391.  
  392. static int
  393. curses_swap(const struct sessmgr_sw *sm, void *old, void *new)
  394. {
  395.     if (new)
  396.     {
  397.     clearok(((struct curses_data *) new)->win, TRUE);
  398.     touchwin(((struct curses_data *) new)->win);
  399.     curscreen = new;
  400.     }
  401.     return 1;            /* can always run concurrent output */
  402. }
  403.  
  404. static void
  405. wiach(WINDOW *win, chtype ch, int insert)
  406. {
  407.     if (insert)
  408.     winsch(win, (chtype) ch);
  409.     else
  410.     waddch(win, (chtype) ch);
  411. }
  412.  
  413. static void
  414. curses_putch(const struct sessmgr_sw *sm, void *dp, int c)
  415. {
  416.     register struct curses_data *sp;
  417.     int x, y, ox, oy;
  418.     chtype attrs;
  419.  
  420.     sp = dp;
  421.     if (c == 7)
  422.     {
  423.     write(1, "\7", 1);
  424.     return;
  425.     }
  426.     if (c == '\r' || c == '\b')
  427.     {
  428.     waddch(sp->win, (chtype) c);
  429.     return;
  430.     }
  431.     if (c == '\t')
  432.     {
  433.     wiach(sp->win, (chtype) c, sp->flags & C_INS);
  434.     return;
  435.     }
  436.     if (c == '\n')
  437.     {
  438.     /* waddch() does clrtoeol() implicitly.  This breaks us. */
  439.     getyx(sp->win, y, x);
  440.     if (++y > sp->win->_bmarg)
  441.     {
  442.         y--;
  443.         scroll(sp->win);
  444.     }
  445.     wmove(sp->win, y, 0);
  446.     return;
  447.     }
  448.     if (sp->flags & C_TTY)
  449.     {
  450.     if (c >= 32 && c < 127)
  451.         wiach(sp->win, (chtype) c, sp->flags & C_INS);
  452.     return;
  453.     }
  454.     if (c == 24 || c == 26)
  455.     {
  456.     sp->flags &= ~(C_ESC|C_CSI);
  457.     return;
  458.     }
  459.     if (c == 27)
  460.     {
  461.     sp->flags |= C_ESC;
  462.     return;
  463.     }
  464.     if (c == '\016')
  465.     {
  466.     wattron(sp->win, A_ALTCHARSET);
  467.     return;
  468.     }
  469.     if (c == '\017')
  470.     {
  471.     wattroff(sp->win, A_ALTCHARSET);
  472.     return;
  473.     }
  474.     if (c < 32)
  475.     return;
  476.     if (!(sp->flags & (C_ESC|C_CSI)))
  477.     {
  478.     if (c > 127 && ibm_map[c - 128])
  479.         wiach(sp->win, ibm_map[c - 128] | A_ALTCHARSET, sp->flags & C_INS);
  480.     else if (c < 127)
  481.         wiach(sp->win, (chtype) c, sp->flags & C_INS);
  482.     return;
  483.     }
  484.     if (sp->flags & C_ESC)
  485.     {
  486.     /* we only handle '[' */
  487.     switch (c)
  488.     {
  489.     case '[':
  490.         sp->flags &= ~C_ESC;
  491.         sp->flags |= C_CSI;
  492.         sp->nparm = 0;
  493.         memset(sp->parm, 0, sizeof sp->parm);
  494.         break;
  495.     case '7':
  496.         getyx(sp->win, sp->save.y, sp->save.x);
  497.         sp->save.attr = getattrs(sp->win);
  498.         sp->save.tmarg = sp->win->_tmarg;
  499.         sp->save.bmarg = sp->win->_bmarg;
  500.         sp->save.bkgd = sp->win->_bkgd; /* should be a macro for this */
  501.         sp->save.valid = 1;
  502.         sp->flags &= ~(C_ESC|C_CSI);
  503.         break;
  504.     case '8':
  505.         if (sp->save.valid)
  506.         {
  507.         wmove(sp->win, sp->save.y, sp->save.x);
  508.         wattrset(sp->win, sp->save.attr);
  509.         wbkgdset(sp->win, sp->save.bkgd);
  510. #ifdef linux
  511.         werase(sp->win); /* wbkgdset() doesn't do anything */
  512. #endif
  513.         wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
  514.         sp->save.valid = 0;
  515.         }
  516.         sp->flags &= ~(C_ESC|C_CSI);
  517.         break;
  518.     default:
  519.         sp->flags &= ~(C_ESC|C_CSI);
  520.         break;
  521.     }
  522.     return;
  523.     }
  524.     /* handle CSI-sequences */
  525.     switch (c)
  526.     {
  527.     case '0':
  528.     case '1':
  529.     case '2':
  530.     case '3':
  531.     case '4':
  532.     case '5':
  533.     case '6':
  534.     case '7':
  535.     case '8':
  536.     case '9':
  537.     sp->parm[sp->nparm] = sp->parm[sp->nparm] * 10 + c - '0';
  538.     break;
  539.     case ';':
  540.     sp->parm[sp->nparm++] = 0;
  541.     break;
  542.     case '?':
  543.     /* just ignore it for now */
  544.     break;
  545.     /* action character */
  546.     case 'H':
  547.     case 'f':
  548.     wmove(sp->win, sp->parm[1] - 1, sp->parm[0] - 1);
  549.     sp->flags &= ~(C_ESC|C_CSI);
  550.     break;
  551.     case 'J':
  552.     switch (sp->parm[0])
  553.     {
  554.     case 0:
  555.         attrs = getattrs(sp->win);
  556.         wattrset(sp->win, A_NORMAL);
  557.         wclrtobot(sp->win);
  558.         wattrset(sp->win, attrs);
  559.         break;
  560.     case 1:
  561.         getyx(sp->win, oy, ox);
  562.         attrs = getattrs(sp->win);
  563.         wattrset(sp->win, A_NORMAL);
  564.         for (y = 0; y < oy; y++)
  565.         {
  566.         wmove(sp->win, y, 0);
  567.         for (x = Getmaxx(sp->win); x--; )
  568.             waddch(sp->win, ' ');
  569.         }
  570.         wmove(sp->win, oy, 0);
  571.         for (x = 0; x < ox; x++)
  572.         waddch(sp->win, ' ');
  573.         wattrset(sp->win, attrs);
  574.         break;
  575.     case 2:
  576.         wclear(sp->win);
  577.         break;
  578.     }
  579.     sp->flags &= ~(C_ESC|C_CSI);
  580.     break;
  581.     case 'K':
  582.     switch (sp->parm[0])
  583.     {
  584.     case 0:
  585.         clrtoeol();
  586.         break;
  587.     case 1:
  588.         getyx(sp->win, oy, ox);
  589.         wmove(sp->win, oy, 0);
  590.         attrs = getattrs(sp->win);
  591.         wattrset(sp->win, A_NORMAL);
  592.         for (x = 0; x < ox; x++)
  593.         waddch(sp->win, ' ');
  594.         wattrset(sp->win, attrs);
  595.         break;
  596.     case 2:
  597.         getyx(sp->win, oy, ox);
  598.         wmove(sp->win, oy, 0);
  599.         attrs = getattrs(sp->win);
  600.         wattrset(sp->win, A_NORMAL);
  601.         for (x = Getmaxx(sp->win); x--; )
  602.         waddch(sp->win, ' ');
  603.         wmove(sp->win, oy, ox);
  604.         wattrset(sp->win, attrs);
  605.         break;
  606.     }
  607.     sp->flags &= ~(C_ESC|C_CSI);
  608.     break;
  609.     case 'm':
  610.     sp->flags &= ~(C_ESC|C_CSI);
  611.     if (!sp->nparm)
  612.     {
  613.         wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
  614.         break;
  615.     }
  616.     for (x = 0; x < sp->nparm; x++)
  617.     {
  618.         switch (sp->parm[x])
  619.         {
  620.         case 0:
  621.         wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
  622.         break;
  623.         case 1:
  624.         wattron(sp->win, A_BOLD);
  625.         break;
  626.         case 2:
  627.         wattron(sp->win, A_DIM);
  628.         break;
  629.         case 4:
  630.         wattron(sp->win, A_UNDERLINE);
  631.         break;
  632.         case 5:
  633.         wattron(sp->win, A_BLINK);
  634.         break;
  635.         case 7:
  636.         wattron(sp->win, A_REVERSE);
  637.         break;
  638.         case 21:
  639.         wattroff(sp->win, A_BOLD);
  640.         break;
  641.         case 22:
  642.         wattroff(sp->win, A_DIM);
  643.         break;
  644.         case 24:
  645.         wattroff(sp->win, A_UNDERLINE);
  646.         break;
  647.         case 25:
  648.         wattroff(sp->win, A_BLINK);
  649.         break;
  650.         case 27:
  651.         wattroff(sp->win, A_REVERSE);
  652.         break;
  653.         /* ANSI color sequences? */
  654.         /* not for now; curses colors are too complex */
  655.         }
  656.     }
  657.     break;
  658.     case 'A':
  659.     getyx(sp->win, y, x);
  660.     if ((y -= (sp->nparm? sp->parm[0]: 1)) < 0)
  661.         y = 0;
  662.     wmove(sp->win, y, x);
  663.     sp->flags &= ~(C_ESC|C_CSI);
  664.     break;
  665.     case 'B':
  666.     getyx(sp->win, y, x);
  667.     if ((y += (sp->nparm? sp->parm[0]: 1)) >= Getmaxy(sp->win))
  668.         y = Getmaxy(sp->win) - 1;
  669.     wmove(sp->win, y, x);
  670.     sp->flags &= ~(C_ESC|C_CSI);
  671.     break;
  672.     case 'C':
  673.     getyx(sp->win, y, x);
  674.     if ((x += (sp->nparm? sp->parm[0]: 1)) >= Getmaxx(sp->win))
  675.         x = Getmaxx(sp->win) - 1;
  676.     wmove(sp->win, y, x);
  677.     sp->flags &= ~(C_ESC|C_CSI);
  678.     break;
  679.     case 'D':
  680.     getyx(sp->win, y, x);
  681.     if ((x -= (sp->nparm? sp->parm[0]: 1)) < 0)
  682.         x = 0;
  683.     wmove(sp->win, y, x);
  684.     sp->flags &= ~(C_ESC|C_CSI);
  685.     break;
  686.     case 'r':
  687.     wsetscrreg(sp->win, (sp->nparm? sp->parm[0] - 1: 0),
  688.            (sp->nparm > 1? sp->parm[1] - 1: Getmaxy(sp->win) - 1));
  689.     sp->flags &= ~(C_ESC|C_CSI);
  690.     break;
  691.     case 's':
  692.     getyx(sp->win, sp->save.y, sp->save.x);
  693.     sp->save.attr = getattrs(sp->win);
  694.     sp->save.tmarg = sp->win->_tmarg;
  695.     sp->save.bmarg = sp->win->_bmarg;
  696.     sp->save.bkgd = sp->win->_bkgd; /* should be a macro for this */
  697.     sp->save.valid = 1;
  698.     sp->flags &= ~(C_ESC|C_CSI);
  699.     break;
  700.     case 'u':
  701.     if (sp->save.valid)
  702.     {
  703.         wmove(sp->win, sp->save.y, sp->save.x);
  704.         wattrset(sp->win, sp->save.attr);
  705.         wbkgdset(sp->win, sp->save.bkgd);
  706.         wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
  707.         sp->save.valid = 0;
  708.     }
  709.     sp->flags &= ~(C_ESC|C_CSI);
  710.     break;
  711.     case 'L':
  712.     if (!sp->nparm)
  713.         sp->parm[0] = 1;
  714.     while (sp->parm[0]--)
  715.         winsertln(sp->win);
  716.     sp->flags &= ~(C_ESC|C_CSI);
  717.     break;
  718.     case 'M':
  719.     if (!sp->nparm)
  720.         sp->parm[0] = 1;
  721.     while (sp->parm[0]--)
  722.         wdeleteln(sp->win);
  723.     sp->flags &= ~(C_ESC|C_CSI);
  724.     break;
  725.     case '@':
  726.     if (!sp->nparm)
  727.         sp->parm[0] = 1;
  728.     while (sp->parm[0]--)
  729.         winsch(sp->win, ' ');
  730.     sp->flags &= ~(C_ESC|C_CSI);
  731.     break;
  732.     case 'P':
  733.     if (!sp->nparm)
  734.         sp->parm[0] = 1;
  735.     while (sp->parm[0]--)
  736.         wdelch(sp->win);
  737.     sp->flags &= ~(C_ESC|C_CSI);
  738.     break;
  739.     case 'h':
  740.     case 'l':
  741.     for (x = 0; x < sp->nparm; x++)
  742.     {
  743.         switch (sp->parm[x])
  744.         {
  745.         case 4:
  746.         if (c == 'h')
  747.             sp->flags |= C_INS;
  748.         else
  749.             sp->flags &= ~C_INS;
  750.         break;
  751.         /* insert mode is all we handle right now */
  752.         }
  753.     }
  754.     sp->flags &= ~(C_ESC|C_CSI);
  755.     break;
  756.     default:
  757.     sp->flags &= ~(C_ESC|C_CSI);
  758.     break;
  759.     }
  760. }
  761.  
  762. static void
  763. curses_clreol(const struct sessmgr_sw *sm, void *dp)
  764. {
  765.     wclrtoeol(((struct curses_data *) dp)->win);
  766. }
  767.  
  768. static void
  769. curses_rflush(const struct sessmgr_sw *sm, void *dp)
  770. {
  771.     /* stub - later we'll update status here */
  772. }
  773.  
  774. static void
  775. curses_flush(const struct sessmgr_sw *sm, void *dp)
  776. {
  777.     if (!Suspense && curscreen == dp)
  778.     wrefresh(((struct curses_data *) dp)->win);
  779. }
  780.  
  781. static void *
  782. curses_create(const struct sessmgr_sw *sm, struct session *sp)
  783. {
  784.     struct curses_data *ssp;
  785.  
  786.     ssp = mallocw(sizeof *ssp);
  787.     ssp->win = newwin(LINES, COLS, 0, 0);
  788.     scrollok(ssp->win, TRUE);
  789. #if 0
  790.     ssp->bg = COLOR_BLACK;    /* witness help 'em if they're in an xterm */
  791.     ssp->fg = COLOR_WHITE;
  792.     wbkgdset(ssp->win, COLOR_PAIR(1));
  793.     wattrset(ssp->win, COLOR_PAIR(1));
  794. #endif
  795.     ssp->flags = 0;
  796.     ssp->save.valid = 0;
  797.     curscreen = ssp;
  798.     return ssp;
  799. }
  800.  
  801. static void
  802. curses_destroy(const struct sessmgr_sw *sm, void *dp)
  803. {
  804.     delwin(((struct curses_data *) dp)->win);
  805.     j_free(dp);
  806. }
  807.  
  808. static void
  809. curses_clrscr(const struct sessmgr_sw *sm, void *dp)
  810. {
  811.     WINDOW *w;
  812.     int l;
  813.  
  814.     w = ((struct curses_data *) dp)->win;
  815.     for (l = w->_tmarg; l < w->_bmarg; l++)
  816.     {
  817.     wmove(w, l, 0);
  818.     wclrtoeol(w);
  819.     }
  820.     wmove(w, w->_tmarg, 0);
  821. }
  822.  
  823. static int
  824. curses_wherex(const struct sessmgr_sw *sm, void *dp)
  825. {
  826.     int x, y;
  827.  
  828.     getyx(((struct curses_data *) dp)->win, y, x);
  829.     return x + 1;
  830. }
  831.  
  832. static int
  833. curses_wherey(const struct sessmgr_sw *sm, void *dp)
  834. {
  835.     WINDOW *w;
  836.     int x, y;
  837.  
  838.     w = ((struct curses_data *) dp)->win;
  839.     getyx(w, y, x);
  840.     return y - w->_tmarg + 1;
  841. }
  842.  
  843. static void
  844. curses_window(const struct sessmgr_sw *sm, void *dp, int x1, int y1, int x2,
  845.           int y2)
  846. {
  847.     WINDOW *w;
  848.  
  849.     w = ((struct curses_data *) dp)->win;
  850.     wsetscrreg(w, y1 - 1, y2 - 1);
  851.     /* ttydriv() assumes the cursor is placed in this window somewhere */
  852.     wmove(w, y1 - 1, 0);
  853. }
  854.  
  855. static void
  856. curses_gotoxy(const struct sessmgr_sw *sm, void *dp, int x, int y)
  857. {
  858.     WINDOW *w;
  859.  
  860.     w = ((struct curses_data *) dp)->win;
  861.     wmove(w, y + w->_tmarg - 1, x - 1);
  862. }
  863.  
  864. static void
  865. curses_high(const struct sessmgr_sw *sm, void *dp)
  866. {
  867.     wattron(((struct curses_data *) dp)->win,
  868.         (((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE);
  869. }
  870.  
  871. static void
  872. curses_norm(const struct sessmgr_sw *sm, void *dp)
  873. {
  874.     wattroff(((struct curses_data *) dp)->win,
  875.          (((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE);
  876. }
  877.  
  878. #if 0
  879.  
  880. static int
  881. color_name(char *color)
  882. {
  883.     if (strcasecmp(color, "black") == 0)
  884.     return COLOR_BLACK;
  885.     if (strcasecmp(color, "red") == 0)
  886.     return COLOR_RED;
  887.     if (strcasecmp(color, "yellow") == 0)
  888.     return COLOR_YELLOW;
  889.     if (strcasecmp(color, "green") == 0)
  890.     return COLOR_GREEN;
  891.     if (strcasecmp(color, "blue") == 0)
  892.     return COLOR_BLUE;
  893.     if (strcasecmp(color, "magenta") == 0)
  894.     return COLOR_MAGENTA;
  895.     if (strcasecmp(color, "cyan") == 0)
  896.     return COLOR_CYAN;
  897.     return COLOR_WHITE;
  898. }
  899.  
  900. #endif
  901.  
  902. static void
  903. curses_cursor(const struct sessmgr_sw *sm, void *dp, int c)
  904. {
  905.     curs_set(c);
  906. }
  907.  
  908. static int
  909. kbchar(int ir)
  910. {
  911.     extern int Keyboard;
  912.     unsigned char ch;
  913.     int i;
  914.  
  915.     if (ir)
  916.     j_alarm(500);
  917.     do
  918.     {
  919.     if (pwait(&Keyboard) != 0 && ir)
  920.         return -1;
  921.     }
  922.     while ((i = read(0, &ch, 1)) == 0 || (i == -1 && errno == EWOULDBLOCK));
  923.     j_alarm(0);
  924.     if (i < 0)
  925.     {
  926.     tprintf("NOS PANIC: Lost keyboard\n");
  927.     where_outta_here(1);
  928.     }
  929.     return ch;
  930. }
  931.  
  932. /*
  933.  * This remains incorrect.  The keyboard process must be recreated as part of
  934.  * the session manager instead of being independent; this process must be
  935.  * capable of distributing input from several sources, including the real
  936.  * keyboard and external sessions.
  937.  */
  938.  
  939. static int
  940. curses_kbread(const struct sessmgr_sw *sm, void *dp)
  941. {
  942.     static int ungets[10];
  943.     struct keytrie *t;
  944.     static int unget;
  945.     int ungetc[10];
  946.     int c, i, u;
  947.  
  948.     i = 0;
  949.     u = 0;
  950.     if (unget > i)
  951.     c = ungets[i++];
  952.     else
  953.     c = kbchar(0);
  954.     ungetc[u++] = c;
  955.     t = keys;
  956.     while (t[c].kt_type == KT_TRIE || t[c].kt_type == KT_TVAL)
  957.     {
  958.     t = t[c].kt_trie;
  959.     if (unget > i)
  960.         c = ungets[i++];
  961.     else
  962.         c = kbchar(1);
  963.     if (c == -1)
  964.         break;
  965.     ungetc[u++] = c;
  966.     }
  967.     if (t[c].kt_type == KT_VAL)
  968.     {
  969.     u = 0;
  970.     c = t[c].kt_val;
  971.     }
  972.     else if (t[c].kt_type == KT_TVAL)
  973.     {
  974.     u = 0;
  975.     c = t[c].kt_tval;
  976.     }
  977.     while (i < unget)
  978.     ungetc[u++] = ungets[i++];
  979.     if (u)
  980.     {
  981.     c = ungetc[0];
  982.     for (i = u; i; i--)
  983.         ungets[i - 1] = ungetc[i];
  984.     unget = u - 1;
  985.     }
  986.     return c;
  987. }
  988.  
  989. struct sessmgr_sw curses_sessmgr =
  990. {
  991.     "curses",
  992.     SM_SPLIT|SM_STDIO,
  993.     curses_init,
  994.     (char *(*)__FARGS((const struct sessmgr_sw *, char *))) 0,
  995.     curses_create,
  996.     curses_opts,
  997.     curses_swap,
  998.     curses_putch,
  999.     curses_clreol,
  1000.     curses_clrscr,
  1001.     curses_wherex,
  1002.     curses_wherey,
  1003.     curses_window,
  1004.     curses_gotoxy,
  1005.     curses_high,
  1006.     curses_norm,
  1007.     curses_cursor,
  1008.     curses_kbread,
  1009.     curses_destroy,
  1010.     0,
  1011.     curses_rflush,
  1012.     curses_flush,
  1013.     curses_suspend,
  1014.     curses_resume,
  1015.     curses_end,
  1016. };
  1017.  
  1018. #endif
  1019.